<template>
  <div class="row padding-page q-ma-md">
    <q-card class="col-12" flat bordered>
      <!-- 上面的卡片标题 -->
      <q-card-section class="row col-12">
        <div class="q-pr-lg">
          <div class="text-subtitle1 text-bold text-primary">
            {{ rnaQTL(queryQTLType) }}s (significant associations between MNVs
            and miRNA expression) across different cancer types
          </div>
          <div class="text-body2">
            In {{ rnaQTL(queryQTLType) }} analysis, we identified
            {{ qtlCount[queryQTLType].cis }} cis-{{ rnaQTL(queryQTLType) }}s and
            {{ qtlCount[queryQTLType].trans }} trans-{{ rnaQTL(queryQTLType) }}s
            at FDR &lt; 0.10 in 33 cancer types for users to search or browse.
          </div>
        </div>
        <div>
          <q-btn
            class="absolute-right"
            color="primary"
            flat
            dense
            :icon="formExpand ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
            :ripple="false"
            @click="formExpand = !formExpand"
          />
        </div>
      </q-card-section>
      <q-separator />
      <!-- 表单内容 -->
      <q-form v-show="formExpand" @submit="onSubmit" @reset="onReset">
        <!-- 表单主体 -->
        <q-card-section
          class="row col-12 justify-center q-gutter-x-md q-gutter-y-sm"
        >
          <!-- 癌症类型 -->
          <q-select
            class="col-12 col-sm-2"
            :dense="smallScreen"
            v-model="queryCancer"
            use-input
            input-debounce="0"
            label="Cancer Type"
            :options="filteredCancerList"
            @filter="onCancerFilter"
          >
            <template v-slot:no-option>
              <q-item>
                <q-item-section class="text-grey"> No results </q-item-section>
              </q-item>
            </template>
          </q-select>
          <!-- MNV查询 -->
          <q-input
            class="col-12 col-sm-3"
            clearable
            :dense="smallScreen"
            hide-bottom-space
            lazy-rules="ondemand"
            ref="inputVariantRef"
            v-model="queryVariant"
            label="MNV (rsID or genomic region)"
            :rules="queryRules"
          />
          <!-- 表型查询 -->
          <q-input
            class="col-12 col-sm-3"
            clearable
            :dense="smallScreen"
            hide-bottom-space
            lazy-rules="ondemand"
            ref="inputTraitRef"
            v-model="queryTrait"
            label="miRNA ID or miRNA name"
            :rules="queryRules"
          />
          <q-select
            class="col-12 col-sm-1"
            :dense="smallScreen"
            v-model="fdrFilter"
            label="FDR"
            :options="['0.05', '0.10']"
          >
          </q-select>
        </q-card-section>
        <!-- 表单按钮 -->
        <q-card-section
          class="row col-12 justify-center items-center q-gutter-x-xl q-gutter-y-sm q-py-none"
        >
          <q-btn
            class="col-10 col-sm-auto"
            no-caps
            unelevated
            icon="search"
            color="indigo-6"
            label="Search cis"
            size="md"
            @click="onSubmit('cis')"
          />
          <q-btn
            class="col-10 col-sm-auto"
            no-caps
            unelevated
            icon="search"
            color="indigo-6"
            label="Search trans"
            size="md"
            @click="onSubmit('trans')"
          />
          <q-btn
            class="col-10 col-sm-auto"
            no-caps
            unelevated
            icon="refresh"
            color="negative"
            label="Reset"
            size="md"
            @click="onReset"
          />
        </q-card-section>
        <!-- 查询提示 -->
        <q-card-section
          class="row col-12 justify-center q-gutter-x-md q-gutter-y-xs"
        >
          <span class="col-auto self-center">Search examples:</span>
          <q-btn
            class="row col-auto text-body2"
            no-caps
            flat
            :ripple="false"
            v-for="example in searchExamples"
            :key="example.query"
            :label="example.query === '' ? example.trait : example.query"
            @click="queryExample(example)"
            color="secondary"
            text-color="primary"
          />
        </q-card-section>
      </q-form>
    </q-card>
  </div>
  <div class="row padding-page q-ma-md">
    <q-card class="col-12 q-pa-md" flat bordered>
      <q-card-section class="no-padding">
        <q-table
          flat
          row-key="label"
          v-model:pagination="tablePagination"
          :rows="tableRows"
          :columns="tableColumns"
          :dense="smallScreen"
          :loading="tableLoading"
          :rows-per-page-options="[10, 20, 50]"
          :pagination-label="
            (firstRowIndex, endRowIndex, totalRowsNumber) =>
              `${firstRowIndex}~${endRowIndex} / ${totalRowsNumber}`
          "
          @request="onRequest"
        >
          <template v-slot:loading>
            <q-inner-loading showing color="primary" />
          </template>
          <template v-slot:top="props">
            <div class="row col-12">
              <q-space />
              <div class="row q-gutter-x-sm">
                <q-btn
                  flat
                  :ripple="false"
                  dense
                  :icon="props.inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
                  @click="props.toggleFullscreen"
                />
                <q-btn
                  icon="file_download"
                  no-caps
                  flat
                  :ripple="false"
                  dense
                  @click="exportTable"
                />
              </div>
            </div>
          </template>
          <template v-slot:header="props">
            <q-tr :props="props">
              <q-th
                v-for="col in props.cols"
                :key="col.name"
                :props="props"
                style="
                  font-weight: bold;
                  font-size: 14px;
                  color: var(--q-primary);
                "
              >
                {{ col.label }}
              </q-th>
            </q-tr>
          </template>
          <template v-slot:body-cell-QTL_type="props">
            <q-td class="text-center" key="QTL_type" :props="props">
              <q-badge
                :color="
                  qtl_color[props.row.QTL_type.replace(/cis-|trans-/, '', 'gi')]
                "
              >
                {{ props.row.QTL_type.match(/cis-|trans-/, '', 'gi')[0]
                }}{{
                  rnaQTL(props.row.QTL_type.replace(/cis-|trans-/, '', 'gi'))
                }}
              </q-badge>
            </q-td>
          </template>
          <template v-slot:body-cell-plot="props">
            <q-td key="plot" :props="props">
              <q-btn
                size="md"
                color="primary"
                icon="bar_chart"
                dense
                rounded
                outline
                @click="showBoxplot(props.row)"
              >
                <q-tooltip> Show boxplot </q-tooltip>
              </q-btn>
            </q-td>
          </template>
        </q-table>
      </q-card-section>
    </q-card>
  </div>
  <q-dialog v-model="modalShow">
    <q-card style="width: 600px; height: 600px">
      <q-card-section>
        <BoxPlot
          :xlabel="boxPlotOptions.xlabel"
          :cancer="boxPlotOptions.cancer"
          :qtl="boxPlotOptions.qtl"
          :ylabel="boxPlotOptions.ylabel"
          :smaples="boxPlotOptions.samples"
          :data="boxPlotOptions.data"
        />
      </q-card-section>
    </q-card>
  </q-dialog>
</template>

<script setup lang="ts">
import { exportFile, useQuasar } from 'quasar';
import { ref, computed, onMounted, reactive } from 'vue';

import { qtlType } from 'src/interface/qtlType';
import { qtlResultColumns } from 'src/model/qtlResult';
import { queryQTL } from 'src/apis/queryQTL';
import { queryBoxplot } from 'src/apis/queryBoxplot';
import { cancerType } from 'src/interface/cancerType';

import BoxPlot from 'src/components/BoxPlot.vue';
import { qtlColorType } from 'src/interface/qtlColor';

import { getDataCounts } from 'src/boot/dataCount';

const $q = useQuasar();
const smallScreen = computed((): boolean => {
  return !$q.screen.gt.sm;
});

const qtl_color: qtlColorType = {
  apaQTL: 'orange-6',
  eQTL: 'red-6',
  lnceQTL: 'teal-6',
  mireQTL: 'light-green-6',
  meQTL: 'purple-6',
  sQTL: 'light-blue-6',
};
const qtl_pheno_name: qtlColorType = {
  apaQTL: 'APA_events',
  eQTL: 'GENE_id',
  lnceQTL: 'lncRNA_id',
  mireQTL: 'miRNA_name',
  meQTL: 'probe_id',
  sQTL: 'SPLICE_id',
};
const quantityName: qtlColorType = {
  apaQTL: 'PDUI',
  eQTL: 'Expression (log2(FPKM)+1)',
  lnceQTL: 'Expression (log2(FPKM)+1)',
  mireQTL: 'Expression (log2(TPM)+1)',
  meQTL: 'Beta',
  sQTL: 'PSI',
};
const pheno_marker_header_list = {
  apaQTL: 'APA_events',
  eQTL: 'GENE_name',
  lnceQTL: 'lncRNA_name',
  mireQTL: 'miRNA_name',
  sQTL: 'SPLICE_id',
  meQTL: 'probe_id',
};
const dataStat = getDataCounts()

const qtlCount = {
  apaQTL: {
    cis: dataStat.qtl.cis.apaQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.apaQTL.reduce((a, b) => a + b, 0),
  },
  eQTL: {
    cis: dataStat.qtl.cis.eQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.eQTL.reduce((a, b) => a + b, 0),
  },
  lnceQTL: {
    cis: dataStat.qtl.cis.lnceQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.lnceQTL.reduce((a, b) => a + b, 0),
  },
  mireQTL: {
    cis: dataStat.qtl.cis.mireQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.mireQTL.reduce((a, b) => a + b, 0),
  },
  meQTL: {
    cis: dataStat.qtl.cis.meQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.meQTL.reduce((a, b) => a + b, 0),
  },
  sQTL: {
    cis: dataStat.qtl.cis.sQTL.reduce((a, b) => a + b, 0),
    trans: dataStat.qtl.trans.sQTL.reduce((a, b) => a + b, 0),
  },
};
const rnaQTL = (rawName: string) => {
  if (rawName == 'lnceQTL') {
    return 'lncRNA-eQTL';
  } else if (rawName == 'mireQTL') {
    return 'miRNA-eQTL';
  } else {
    return rawName;
  }
};

// 查询示例
const searchExamples = [
  {
    query: 'rs56030066',
    cancer_type: 'ALL',
    trait: '',
  },
  {
    query: 'chr6:6034000-6035000',
    cancer_type: 'ALL',
    trait: '',
  },
  {
    query: '',
    cancer_type: 'ALL',
    trait: 'hsa-miR-4772-5p',
  },
  {
    query: '',
    cancer_type: 'ALL',
    trait: 'MIMAT0022720',
  },
];
const queryExample = (params) => {
  queryVariant.value = params.query;
  queryCancer.value = params.cancer_type;
  queryTrait.value = params.trait;
};

// 表单状态以及固定值
const cancerTypeList = [
  'ALL',
  'ACC',
  'BLCA',
  'BRCA',
  'CESC',
  // 'CHOL',
  'COAD',
  'DLBC',
  'ESCA',
  'GBM',
  'HNSC',
  'KICH',
  'KIRC',
  'KIRP',
  'LAML',
  'LGG',
  'LIHC',
  'LUAD',
  'LUSC',
  'MESO',
  'OV',
  'PAAD',
  'PCPG',
  'PRAD',
  'READ',
  'SARC',
  'SKCM',
  'STAD',
  'TGCT',
  'THCA',
  'THYM',
  'UCEC',
  'UCS',
  'UVM',
];
const filteredCancerList = ref(cancerTypeList);
const onCancerFilter = (val, update) => {
  if (val === '') {
    update(() => {
      filteredCancerList.value = cancerTypeList;
    });
    return;
  }
  update(() => {
    const needle = val.toLowerCase();
    filteredCancerList.value = cancerTypeList.filter(
      (v) => v.toLowerCase().indexOf(needle) > -1
    );
  });
};

// 表单查询参数
const queryQTLType = ref<qtlType>('mireQTL');
const queryCancer = ref<cancerType>('ALL');
const queryVariant = ref(null);
const queryTrait = ref(null);
const fdrFilter = ref('0.10');
const inputVariantRef = ref(null);
const inputTraitRef = ref(null);
const currentShow = reactive({
  qtl: queryQTLType.value,
  cancer: 'ALL',
  mnv: null,
  trait: null,
  searchType: 'cis',
  fdr: '0.10',
});
const formExpand = ref(true);

// 表单方法
//TODO 验证规则
const queryRules = [
  (val) => {
    const containSpecial = (s: string) => {
      var containSpecial = RegExp(
        /[(\ )(\~)(\!)(\@)(\#)(\$)(\%)(\^)(\&)(\*)(\()(\))(\+)(\=)(\[)(\])(\{)(\})(\|)(\\)(\;)(\')(\")(\.)(\/)(\<)(\>)(\?)(\)]+/
      );
      return containSpecial.test(s);
    };

    if (!containSpecial(val)) {
      return true;
    } else {
      return 'Can not has special character!';
    }
  },
];

const onSubmit = (searchType: 'cis' | 'trans') => {
  inputVariantRef.value.validate();
  inputTraitRef.value.validate();
  if (!inputVariantRef.value.hasError && !inputTraitRef.value.hasError) {
    currentShow.qtl = queryQTLType.value;
    currentShow.cancer = queryCancer.value;
    currentShow.mnv = queryVariant.value;
    currentShow.trait = queryTrait.value;
    currentShow.searchType = searchType;
    currentShow.fdr = fdrFilter.value;
    tablePagination.value.page = 1;
    fetchData(
      currentShow.mnv,
      currentShow.qtl,
      currentShow.cancer,
      currentShow.trait,
      searchType === 'cis' ? 0 : 1,
      currentShow.fdr
    );
  }
};
const onReset = () => {
  queryQTLType.value = queryQTLType.value;
  queryCancer.value = 'ALL';
  queryVariant.value = null;
  queryTrait.value = null;
  currentShow.qtl = queryQTLType.value;
  currentShow.cancer = 'ALL';
  currentShow.mnv = null;
  currentShow.trait = null;
};

// 查询数据
const fetchData = (
  MNV_id = '',
  QTL_type: qtlType = queryQTLType.value,
  cancer_type: cancerType = 'ALL',
  trait = '',
  searchType: 0 | 1,
  FDR: 0.05 | 0.1 = 0.1,
  page = 1,
  size = 10,
  sortBy = 'P',
  descending: 0 | 1 = 0
) => {
  tableLoading.value = true;
  tableColumns.value = qtlResultColumns[QTL_type];
  queryQTL({
    MNV_id: MNV_id,
    QTL_type: QTL_type,
    cancer_type: cancer_type,
    trait: trait,
    trans: searchType,
    page: page,
    size: size,
    sortBy: sortBy,
    descending: descending,
    FDR: FDR,
  })
    .then((response) => {
      tableRows.value = response.data.data_source;
      tablePagination.value.rowsNumber = response.data.total;
      tableLoading.value = false;
    })
    .catch((error) => {
      tableLoading.value = false;
      $q.dialog({
        title: 'Error',
        html: true,
        message: `Something wrong happened when searching: <br/>${error}`,
      })
        .onOk(() => {
          //
        })
        .onCancel(() => {
          // console.log('Cancel')
        })
        .onDismiss(() => {
          // console.log('I am triggered on both OK and Cancel')
        });
    });
};

// 表格的数据
const tableColumns = ref(qtlResultColumns[queryQTLType.value]);
const tableRows = ref([]);
const tableLoading = ref(true);
const tablePagination = ref({
  sortBy: 'P',
  descending: false,
  page: 1,
  rowsPerPage: 10,
  rowsNumber: 0,
});

// 表格方法
const onRequest = (props) => {
  // 从表格获取当前的分页信息和排序信息
  const { page, rowsPerPage, sortBy, descending } = props.pagination;
  fetchData(
    currentShow.mnv,
    currentShow.qtl,
    currentShow.cancer,
    currentShow.trait,
    currentShow.searchType === 'cis' ? 0 : 1,
    currentShow.fdr,
    page,
    rowsPerPage,
    sortBy,
    descending ? 1 : 0
  );
  // don't forget to update local pagination object
  tablePagination.value.page = page;
  tablePagination.value.rowsPerPage = rowsPerPage;
  tablePagination.value.sortBy = sortBy;
  tablePagination.value.descending = descending;
};

const wrapCsvValue = (val, formatFn, row) => {
  let formatted = formatFn !== void 0 ? formatFn(val, row) : val;
  formatted =
    formatted === void 0 || formatted === null ? '' : String(formatted);
  formatted = formatted.split('"').join('""');
  return `${formatted}`;
};
const exportTable = () => {
  queryQTL({
    QTL_type: currentShow.qtl,
    cancer_type: currentShow.cancer,
    MNV_id: currentShow.MNV_id,
    trait: currentShow.trait,
    trans: 0,
    page: 1,
    size: tablePagination.value.rowsNumber,
    sortBy: 'FDR',
    descending: 0,
    FDR: currentShow.fdr,
  }).then((response) => {
    const content = [
      tableColumns.value
        .slice(1)
        .map((col) => wrapCsvValue(col.label))
        .join('\t'),
    ]
      .concat(
        response.data.data_source.map((row) =>
          tableColumns.value
            .slice(1)
            .map((col) =>
              wrapCsvValue(
                typeof col.field === 'function'
                  ? col.field(row)
                  : row[col.field === void 0 ? col.name : col.field],
                col.format,
                row
              )
            )
            .join('\t')
        )
      )
      .join('\r\n');
    const status = exportFile(
      `${currentShow.qtl === null ? queryQTLType.value : currentShow.qtl}_${
        currentShow.cancer === null ? 'allCancer' : currentShow.cancer
      }_${currentShow.mnv === null ? 'allMNV' : currentShow.mnv}_${
        currentShow.trait === null ? 'allPheno' : currentShow.trait
      }`,
      content,
      'text'
    );

    if (status !== true) {
      $q.notify({
        message: 'Something wrong happened while download...',
        color: 'negative',
        icon: 'warning',
      });
    }
  });
};

const modalShow = ref(false);
const boxPlotOptions = reactive({
  xlabel: '',
  cancer: '',
  qtl: '',
  ylabel: '',
  samples: ['0', '0', '0'],
  data: [[], [], []],
});

const filterBoxPlotData = (data) => {
  let emptyPosition = data.sample.indexOf(0);
  if (emptyPosition > -1) {
    data.data.splice(emptyPosition, 1);
    data.genotype.splice(emptyPosition, 1);
    data.sample.splice(emptyPosition, 1);
    return {
      data: data.data,
      genotype: data.genotype,
      sample: data.sample,
    };
  } else {
    return {
      data: data.data,
      genotype: data.genotype,
      sample: data.sample,
    };
  }
};

const showBoxplot = (params) => {
  queryBoxplot({
    MNV_id: params.MNV_id,
    cancer_type: params.cancer_type,
    QTL_type: params.QTL_type,
    phenotype:
      params[
        qtl_pheno_name[
          params.QTL_type.replace(/cis-|trans-/, '', 'gi') as qtlType
        ]
      ],
  }).then((response) => {
    boxPlotOptions.ylabel = `${quantityName[currentShow.qtl]} of ${
      params[pheno_marker_header_list[currentShow.qtl]]
    }`;
    boxPlotOptions.xlabel = `Genotype of \n${response.data.MNV_id}`;
    boxPlotOptions.cancer = response.data.cancer_type;
    boxPlotOptions.qtl = response.data.QTL_type;
    boxPlotOptions.samples = filterBoxPlotData(response.data).sample;
    boxPlotOptions.data = filterBoxPlotData(response.data).data;
    modalShow.value = true;
  });
};

// 初始化行为
onMounted(() => {
  tableLoading.value = true;
  queryQTL({
    QTL_type: queryQTLType.value,
    cancer_type: 'ALL',
    trans: 0,
    page: 1,
    size: 10,
  })
    .then((response) => {
      if (response.data.total > 0) {
        tablePagination.value.rowsNumber = response.data.total;
        tableColumns.value = qtlResultColumns[queryQTLType.value];
        tableRows.value = response.data.data_source;
        tableLoading.value = false;
      } else {
        tableLoading.value = false;
        $q.dialog({
          title: 'Warning',
          message: 'No results found, please try another',
        })
          .onOk(() => {
            // console.log('')
          })
          .onCancel(() => {
            // console.log('Cancel')
          })
          .onDismiss(() => {
            // console.log('I am triggered on both OK and Cancel')
          });
      }
    })
    .catch((error) => {
      tableLoading.value = false;
      $q.dialog({
        title: 'Error',
        html: true,
        message: `Something wrong happened when searching: <br/>${error}`,
      })
        .onOk(() => {
          //
        })
        .onCancel(() => {
          // console.log('Cancel')
        })
        .onDismiss(() => {
          // console.log('I am triggered on both OK and Cancel')
        });
    });
});
</script>

<style scoped lang="less"></style>
